#ifndef _LIST_H
#define _LIST_H

#include <common.h>
#include <compiler.h>

typedef struct list_head {
    struct list_head* next, * prev;
} lnode_t;

static inline int list_empty(lnode_t* elem) {
    return elem->next == elem && elem->prev == elem;
}

static inline void list_head_init(lnode_t* head) {
    head->next = head->prev = head;
}

static inline void _list_add(lnode_t* prev, lnode_t* next, lnode_t* elem) {
    next->prev = elem;
    elem->next = next;
    elem->prev = prev;
    prev->next = elem;
}

static inline void list_append(lnode_t* head, lnode_t* elem) {
    _list_add(head->prev, head, elem);
}

static inline void list_prepend(lnode_t* head, lnode_t* elem) {
    _list_add(head, head->next, elem);
}

static inline void list_remove(lnode_t* elem) {
    elem->prev->next = elem->next;
    elem->next->prev = elem->prev;
    elem->next = elem->prev = elem;
}

/**
 * list_entry - get the struct for this entry
 * @ptr:    the &lnode_t pointer.
 * @type:   the type of the struct this is embedded in.
 * @member: the list_head member within the struct.
 */
#define list_entry(ptr, type, member) container_of(ptr, type, member)

 /**
  * list_for_each - iterate over a list
  * @pos:    the &lnode_t to use as a loop counter.
  * @nxt:    the next &lnode_t to use as a loop counter.
  * @head:   the head for your list.
  * @member: the name of the list_head within the struct.
  */
#define list_for_each(pos, nxt, head, member) \
    for (pos = list_entry((head)->next, typeof(*(pos)), member),            \
         nxt = list_entry(pos->member.next, typeof(*(pos)), member);        \
         &pos->member != (head);                                            \
         pos = nxt, nxt = list_entry(nxt->member.next, typeof(*(nxt)), member))

#define list_for_each_entry(pos, head, member) \
    for (pos = list_entry((head)->next, typeof(*(pos)), member);    \
         &pos->member != (head);                                    \
         pos = list_entry(pos->member.next, typeof(*(pos)), member))

#define list_for_each_reverse_to_head(pos, head, member) \
for (pos = list_entry(pos->member.prev, typeof(*(pos)), member); \
    &pos->member != (head); \
    pos = list_entry(pos->member.prev, typeof(*(pos)), member))

typedef struct hlist_head {
    struct hlist_head* next, ** pprev;
} hlnode_t;

static inline void hlist_remove(hlnode_t* node) {
    if (!node->pprev)
        return;
    *node->pprev = node->next;
    node->next = NULL;
    node->pprev = NULL;
}

static inline void hlist_add(hlnode_t** head, hlnode_t* node) {
    node->next = *head;
    if (*head) {
        (*head)->pprev = &node->next;
    }
    node->pprev = head;
    *head = node;
}

#endif /* _LIST_H */